package agency.tango.materialintroscreen.widgets;

import agency.tango.materialintroscreen.adapter.SlidesAdapter;
import agency.tango.materialintroscreen.listeners.GiveTouchToParentListener;
import ohos.agp.components.*;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

import java.util.ArrayList;
import java.util.List;

/**
 * @ProjectName: material-intro-screen-master
 * @Package: agency.tango.materialintroscreen.widgets
 * @ClassName: SwipeableViewPager
 * @Description: 自定义pageslider 可以拦截滑动  特殊条件拦截 权限申请拦截
 * 注册各种不同监听器
 * 实现随着滑动页面颜色渐变 按钮颜色渐变 页面自动回弹
 * @CreateDate: 2021/4/12 18:13
 * @UpdateDate: 2021/4/12 18:13
 * @UpdateRemark: 暂无
 * @Version: 1.0
 */
public class SwipeableViewPager extends PageSlider implements Component.DraggedListener,
        ComponentContainer.TouchEventListener, PageSlider.PageChangedListener {
    private float startPos = 0;
    private float startPosY = 0;
    private int currentIt;
    private boolean swipingAllowed;
    private boolean alphaExitTransitionEnabled = false;
    private List<PageChangedListener> mOnPageChangeListeners;
    private TouchEventListener touchEventListener;
    private GiveTouchToParentListener listener;


    public SwipeableViewPager(Context context) {
        this(context, null);
    }

    public SwipeableViewPager(Context context, AttrSet attrs) {
        this(context, attrs, "");
    }

    public SwipeableViewPager(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        swipingAllowed = true;
        initViewPager();
    }

    private void initViewPager() {
        setDraggedListener(HORIZONTAL, this);
        setOrientation(PageSlider.HORIZONTAL);
        super.setTouchEventListener(this);
        super.addPageChangedListener(this);
        setCentralScrollMode(true);
        setSlidingPossible(false);
    }

    public void setTouchToParentListener(GiveTouchToParentListener listener) {
        this.listener = listener;
    }

    /**
     * Add a listener that will be invoked whenever the page changes or is
     * incrementally
     * scrolled. See {@link PageChangedListener}.
     *
     * <p>Components that add a listener should take care to remove it when
     * finished.
     * Other components that take ownership of a view may call
     * {@link #clearOnPageChangeListeners()}
     * to remove all attached listeners.</p>
     *
     * @param listener listener to add
     */
    public void addOnPageChangeListeners(PageChangedListener listener) {
        if (mOnPageChangeListeners == null) {
            mOnPageChangeListeners = new ArrayList<>();
        }
        mOnPageChangeListeners.add(listener);
    }


    public List<PageChangedListener> getOnPageChangeListeners() {
        return mOnPageChangeListeners;
    }


    @Override
    public void setTouchEventListener(TouchEventListener listener) {
        this.touchEventListener = listener;
    }

    @Override
    public void addPageChangedListener(PageChangedListener listener) {
        if (mOnPageChangeListeners == null) {
            mOnPageChangeListeners = new ArrayList<>();
        }
        if (!mOnPageChangeListeners.contains(listener)) {
            mOnPageChangeListeners.add(listener);
        }
    }

    /**
     * Remove a listener that was previously added via
     * {@link #addOnPageChangeListeners(PageChangedListener)}.
     *
     * @param listener listener to remove
     */
    public void removeOnPageChangeListener(PageChangedListener listener) {
        if (mOnPageChangeListeners != null && mOnPageChangeListeners.contains(listener)) {
            mOnPageChangeListeners.remove(listener);
        }
    }

    /**
     * Remove all listeners that are notified of any changes in scroll state
     * or position.
     */
    public void clearOnPageChangeListeners() {
        if (mOnPageChangeListeners != null) {
            mOnPageChangeListeners.clear();
        }
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {
        boolean avaliable = doTouchEvent(component, event);
        if (touchEventListener != null) {
            return touchEventListener.onTouchEvent(component, event);
        }
        return avaliable;
    }

    private boolean doTouchEvent(Component component, TouchEvent event) {
        int action = event.getAction();

        switch (action) {
            case (TouchEvent.PRIMARY_POINT_DOWN):
                doTouchDown(component, event);
                return true;
            case (TouchEvent.POINT_MOVE):
                float moveX = startPos - event.getPointerScreenPosition(0).getX();
                float moveY = startPosY - event.getPointerScreenPosition(0).getY();
                if (!swipingAllowed && moveX > 0) {
                    setSlidingPossible(false);
                    return true;
                }
                setSlidingPossible(true);
                if (Math.abs(moveY) > Math.abs(moveX)) {
                    return false;
                }
                if (getAdapter() != null && listener != null && getAdapter().isLastSlide(currentIt)) {
                    if (moveX > 0) {
                        listener.onTouchMove(component, event);
                        return false;
                    } else {
                        listener.onTransToOrigin(component, event);
                        return true;
                    }
                } else {
                    return true;
                }
            case (TouchEvent.PRIMARY_POINT_UP):
                float moveUpX = startPos - event.getPointerScreenPosition(0).getX();
                float moveUpY = startPosY - event.getPointerScreenPosition(0).getY();
                if (checkLastSlide(moveUpX)) {
                    listener.onTouchUp(component, event);
                    return false;
                }
                if (!swipingAllowed && moveUpX > 0) {
                    scrollTo(getWidth() * currentIt, 0);
                    return true;
                }
                if (Math.abs(moveUpY) > Math.abs(moveUpX)) {
                    return false;
                }

                startPos = 0;
                break;
            default:
                break;
        }
        return false;
    }

    private boolean checkLastSlide(float moveUpX) {
        return getAdapter() != null && listener != null && moveUpX > 0 && getAdapter().isLastSlide(currentIt);
    }


    public void doTouchDown(Component component, TouchEvent event) {
        startPos = event.getPointerScreenPosition(0).getX();
        startPosY = event.getPointerScreenPosition(0).getY();
        currentIt = getCurrentPage();
        resolveSwipingRightAllowed();
        if (listener != null) {
            listener.onTouchDown(component, event);
        }
    }


    @Override
    public void onDragDown(Component component, DragInfo dragInfo) {
        // do nothing
    }

    @Override
    public void onDragStart(Component component, DragInfo dragInfo) {
        // do nothing
    }

    @Override
    public void onDragUpdate(Component component, DragInfo dragInfo) {
        // do nothing
    }

    @Override
    public void onDragEnd(Component component, DragInfo dragInfo) {
        // do nothing
    }

    @Override
    public void onDragCancel(Component component, DragInfo dragInfo) {
        // do nothing
    }

    /**
     * 获取适配器
     *
     * @return SlidesAdapter
     */
    public SlidesAdapter getAdapter() {
        if (getProvider() instanceof SlidesAdapter) {
            return (SlidesAdapter) getProvider();
        }
        SlidesAdapter slidesAdapter = new SlidesAdapter();
        setProvider(slidesAdapter);
        return slidesAdapter;
    }

    /**
     * 移到下一页
     */
    public void moveToNextPage() {
        setCurrentPage(getCurrentPage() + 1, true);
    }

    /**
     * 获取getPreviousItem
     *
     * @return 上一页
     */
    public int getPreviousItem() {
        if (getCurrentPage() < 1) {
            return 0;
        }
        return getCurrentPage() - 1;
    }

    /**
     * 设置是否可以右滑
     *
     * @param allowed 是否可以右滑
     */
    public void setSwipingRightAllowed(boolean allowed) {
        swipingAllowed = allowed;
    }

    /**
     * 设置页面退出alpha动画是否可用
     *
     * @param alphaExitTransitionEnabled 页面退出alpha动画是否可用
     */
    public void alphaExitTransitionEnabled(boolean alphaExitTransitionEnabled) {
        this.alphaExitTransitionEnabled = alphaExitTransitionEnabled;
    }

    /**
     * 判断页面退出alpha动画是否可用
     *
     * @return 是否可用
     */
    public boolean alphaExitTransitionEnabled() {
        return alphaExitTransitionEnabled && swipingAllowed;
    }

    /**
     * pageslider是否可以右滑
     */
    private void resolveSwipingRightAllowed() {
        if (getAdapter().shouldLockSlide(getCurrentPage())) {
            setSwipingRightAllowed(false);
        } else {
            setSwipingRightAllowed(true);
        }
    }

    @Override
    public void onPageSliding(int position, float positionOffset,
                              int positionOffsetPixels) {
        int tempPosition = position;
        float tempPositionOffset = positionOffset;
        if (getAdapter() == null) {
            return;
        }
        float width = (float) getWidth();
        int currentPage = getCurrentPage();
        float scrollX = 0f;
        if (currentPage >= 0 && currentPage < getAdapter().getCount()
                && getAdapter().getItem(currentPage) != null
                && getAdapter().getItem(currentPage).getRootView() != null) {
            float parentLeft = (float) getLocationOnScreen()[0];
            float itemX = (float) getAdapter().getItem(currentPage).getRootView().getLocationOnScreen()[0];
            scrollX = itemX - parentLeft;
        }

        if (width > 0) {
            if (scrollX <= 0f) {
                tempPosition = currentPage;
                tempPositionOffset = Math.abs(scrollX) / Math.abs(width);
            } else {
                tempPosition = currentPage - 1;
                tempPositionOffset = 1 - (Math.abs(scrollX) / Math.abs(width));
            }
        }
        if (tempPosition >= getAdapter().getCount()) {
            tempPosition = getAdapter().getCount() - 1;
        }
        if (tempPosition < 0) {
            tempPosition = 0;
        }
        if (tempPositionOffset < 0) {
            tempPositionOffset = 0;
        }
        if (tempPositionOffset > 1) {
            tempPositionOffset = 1;
        }
        if (mOnPageChangeListeners == null) {
            return;
        }
        for (int i = 0; i < mOnPageChangeListeners.size(); i++) {
            if (mOnPageChangeListeners.get(i) != null) {
                mOnPageChangeListeners.get(i).onPageSliding(tempPosition,
                        tempPositionOffset, positionOffsetPixels);
            }
        }
    }

    @Override
    public void onPageSlideStateChanged(int state) {
        if (mOnPageChangeListeners == null) {
            return;
        }
        for (int i = 0; i < mOnPageChangeListeners.size(); i++) {
            if (mOnPageChangeListeners.get(i) != null) {
                mOnPageChangeListeners.get(i).onPageSlideStateChanged(state);
            }
        }
    }

    @Override
    public void onPageChosen(int position) {
        if (mOnPageChangeListeners == null) {
            return;
        }
        for (int i = 0; i < mOnPageChangeListeners.size(); i++) {
            if (mOnPageChangeListeners.get(i) != null) {
                mOnPageChangeListeners.get(i).onPageChosen(position);
            }
        }
    }
}